package com.lmt.ymcc.service.impl;

import com.lmt.ymcc.dto.Aggs;
import com.lmt.ymcc.dto.CourseDoc;
import com.lmt.ymcc.dto.CourseEsSearchDto;
import com.lmt.ymcc.esmapper.HighlightResultMapper;
import com.lmt.ymcc.repository.CourseEsRepository;
import com.lmt.ymcc.result.PageList;
import com.lmt.ymcc.service.ICourseEsService;
import com.lmt.ymcc.utils.AggrPageList;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: TODO
 * @Author: Amazing
 * @Date: 2022/8/14 15:38
 * @Version: 1.0
 */
@Service
public class CourseEsServiceImpl implements ICourseEsService {

    @Autowired
    private CourseEsRepository courseEsRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public void saveCourse(CourseDoc doc) {
        courseEsRepository.save(doc);
    }

    @Override
    public void delete(Long id) {
        courseEsRepository.deleteById(id);
    }

    // 分页+条件查询
    @Override
    public PageList<CourseDoc> search(CourseEsSearchDto dto) {
        // 创建SearchQuery的实例对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 设置分页参数
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getRows());
        builder.withPageable(pageRequest);
        // 排序规则
            if (StringUtils.hasLength(dto.getSortField())) {
                String sortName = "";
                switch (dto.getSortField().toLowerCase()) {
                    case "xl" : sortName = "saleCount";break;
                    case "xp" : sortName="onlineTime";break;
                    case "pl" : sortName="commentCount";break;
                    case "jg" : sortName="price";break;
                    case "rq" : sortName="viewCount";break;
                }
                if (StringUtils.hasLength(sortName)) {
                    SortOrder order = SortOrder.ASC;
                    if (StringUtils.hasLength(dto.getSortType())) {
                        order = dto.getSortType().equalsIgnoreCase("DESC") ? SortOrder.DESC : SortOrder.ASC;
                    }
                    builder.withSort(SortBuilders.fieldSort(sortName).order(order));
                }
            }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // keyword搜索
        if (StringUtils.hasLength(dto.getKeyword())) {
            boolQuery.must(QueryBuilders.matchQuery("name", dto.getKeyword()));
        }
        // 设置课程类型
        if (dto.getCourseTypeId() != null) {
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId", dto.getCourseTypeId()));
        }
        // 设置等级名字
        if (StringUtils.hasLength(dto.getGradeName())) {
            boolQuery.filter(QueryBuilders.termQuery("gradeName", dto.getGradeName()));
        }
        // 设置讲师名字
        if (StringUtils.hasLength(dto.getTeacherNames())) {
            boolQuery.filter(QueryBuilders.termQuery("teacherNames", dto.getTeacherNames()));
        }
        // 设置是否收费
        if (StringUtils.hasLength(dto.getChargeName())) {
            boolQuery.filter(QueryBuilders.termQuery("chargeName", dto.getChargeName()));
        }
        // 设置价格区间
        if (dto.getPriceMin() != null) {
            // 设置最小值
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        if (dto.getPriceMax() != null) {
            // 设置最大值
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMax()));
        }
        // 设置高亮
        HighlightBuilder.Field field = new HighlightBuilder.Field("name")
                .preTags("<span style='color : blue'>").postTags("</span>");
        builder.withHighlightFields(field);
        // 设置聚合条件
        builder.addAggregation(AggregationBuilders.terms("gradeNameAgg").field("gradeName")); // 等级
        builder.addAggregation(AggregationBuilders.terms("chargeNameAgg").field("chargeName")); // 收费规则

        //最后通过分页条件进行高级查询（执行查询）
        builder.withQuery(boolQuery);
        NativeSearchQuery query = builder.build();
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(query, CourseDoc.class, highlightResultMapper);
        // Page<CourseDoc> page = courseEsRepository.search(query);
        // 处理结果集
        Map<String, Aggregation> aggsMap = page.getAggregations().asMap();
        Map<String, List<Aggs>> resultMap = new HashMap<>();
        ParsedStringTerms gradeNameAgg = (ParsedStringTerms) aggsMap.get("gradeNameAgg");
        ParsedStringTerms chargeNameAgg = (ParsedStringTerms) aggsMap.get("chargeNameAgg");
        // 把结果转为List<Aggs>集合
        List<Aggs> gradeNameAggList = gradeNameAgg.getBuckets().stream()
                .map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        List<Aggs> chargeNameAggList = chargeNameAgg.getBuckets().stream()
                .map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        // 添加到结果集合中
        resultMap.put("gradeNameAgg", gradeNameAggList);
        resultMap.put("chargeNameAgg", chargeNameAggList);
        // 返回结果集（这里是PageList的子类）
        return new AggrPageList(page.getTotalElements(),page.getContent(),resultMap);
    }
}
